home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 331 / gemfxm14 / memfind.c next >
Encoding:
C/C++ Source or Header  |  1990-07-20  |  12.5 KB  |  337 lines

  1. /**************************************************************************
  2.  *
  3.  * MEMFIND.C - An example program for AESFAST which uses just dialogs.
  4.  *
  5.  *  Public Domain example program by Ian Lepore.
  6.  *
  7.  *  This is distributed as an example of how to write a simple program using
  8.  *  my AESFAST public domain GEM bindings.  This example uses a few of
  9.  *  the nifty utilities from AESFAST, but it's pretty much straightforward
  10.  *  dialog-handling code.
  11.  *
  12.  *  This beast may be marginally useful beyond its value as an example.
  13.  *  It will find and report on the 5 biggest blocks of free memory in 
  14.  *  the system, giving a somewhat more acurate view than programs which
  15.  *  report only the largest free block.
  16.  *
  17.  *  This code is pretty heavily commented.  Please excuse me if some of 
  18.  *  the comments seem obvious, but I figure the audience for this will 
  19.  *  include both beginning C programmers, and old-timers who just need to
  20.  *  see how my bindings work as opposed to other bindings.
  21.  *
  22.  *************************************************************************/
  23.  
  24. #include <gemfast.h>
  25. #include <osbind.h>
  26. #include "memfind.h"
  27.  
  28. #ifndef TRUE
  29. #define TRUE  1
  30. #define FALSE 0
  31. #endif
  32.  
  33. #define NO_RSRC   -2783        /* a random number */
  34.  
  35. /**************************************************************************
  36.  *
  37.  * global vars
  38.  *
  39.  *************************************************************************/
  40.  
  41. typedef struct {
  42.         char *pmem;
  43.         long lmem;
  44.         int  objlink;
  45.         char displaystr[25];
  46.         } MEM_BLOCK;
  47.  
  48. #define NUM_BLOCKS 5
  49.  
  50. MEM_BLOCK mem_ctl[NUM_BLOCKS];
  51.  
  52. OBJECT    *maintree;
  53.  
  54. char map_template[] = "$%06lx    %4dk";    /* template for printf() */
  55.  
  56. char no_rsrc_alert[] = "[3][ | Can't open/load RSC file! | ][ Fatal ]";
  57.  
  58. /**************************************************************************
  59.  *
  60.  * prg_exit - Cleanup and terminate.
  61.  *  If the exit code is our magic number NO_RSRC (indicating that we're
  62.  *  exiting because the resource load failed), we skip the rsrc_free call.
  63.  *
  64.  *************************************************************************/
  65.  
  66. void
  67. prg_exit(code)
  68.         int code;
  69. {
  70.         if (code != NO_RSRC) {
  71.                 rsrc_free();
  72.         }
  73.  
  74.         appl_exit();
  75.         Pterm(code);
  76. }
  77.  
  78. /**************************************************************************
  79.  *
  80.  * prg_init.
  81.  *
  82.  *  This routine does mundance AES init stuff, and makes the connections
  83.  *  between the string objects in the resource tree and the elements in
  84.  *  our memory control array.
  85.  *
  86.  *  The connections concept is based upon accessing arrays of strings in
  87.  *  a dialog box without knowing the actual object indicies (names) of
  88.  *  the string objects.  (Some discussion of this can also be found in 
  89.  *  the MINICOLR accessory example code).  I'll be the first to admit
  90.  *  that this technique is overkill for this little program, since only
  91.  *  five text strings are involved.  On the other hand, you can increase
  92.  *  the number of displayed memory fragments simply by going into the 
  93.  *  resource file and making a few more copies of the display strings, 
  94.  *  then coming into this source code and increasing NUM_BLOCKS to match
  95.  *  the new number of display strings in the resource file.  No other 
  96.  *  changes are necessary, and *that's* something you can't say about
  97.  *  'normal' GEM coding techniques.
  98.  *
  99.  *   What this technique really does is isolate the location of the objects
  100.  *   in the RSC file from the program code.  Thus, a hacker-type can munge
  101.  *   up the resource file and the program will still run correctly, even
  102.  *   if objects are added, deleted, moved, or sorted.
  103.  *
  104.  *   In this implementation, I've set an 'extended object type' on each
  105.  *   of the display string objects, using my resource editor.  I chose
  106.  *   a value of '1' for the extended type, but this is completely 
  107.  *   arbitrary.
  108.  *
  109.  *   Just for grins, I'll list here the code I would have used if I hadn't
  110.  *   implemented the location-independant connections concept.  First, I'll
  111.  *   explain my standard for naming objects...
  112.  *       nnnnttxx
  113.  *       ||||||++--- 2 char arbitrary id (my object name)
  114.  *       ||||++----- object type (see list below)
  115.  *       ++++------- name of the tree holding the object
  116.  *     Object types for naming standards are:
  117.  *        BX  - Button (eXit)
  118.  *        BR  - Button (Radio) (also used for radio boxchars)
  119.  *        ST  - STring
  120.  *        TX  - TeXt (display only)
  121.  *        TE  - Text (Editable)
  122.  *        PB  - Parent Box (usually invisible, parent for radio buttons)
  123.  *        TREE- Special-case name, indicates a root (R_TREE) objct.
  124.  *     Thus, using this standard, you might have:
  125.  *        MAINBXOK - Exit button 'OK' in main dialog box.
  126.  *        DEVSBRDA - Radio Button for drive A in device selection dialog.
  127.  *        MAINSTM1 - Display string M1 in main dialog.
  128.  *
  129.  *   Anyway, enough standards.  You don't have to use my standard, but
  130.  *   I'd advise you to use *some* kind of naming standard that ties object
  131.  *   names to the trees they live in, if you want to maintain your sanity.
  132.  *
  133.  *   So, IF I had done this program in the 'normal' way, the loop below
  134.  *   which does the 'connections' works would be replaced by the following:
  135.  *
  136.  *      rsc_sstrings(maintree,
  137.  *                      MAINSTM1,mem_ctl[0].displaystr,
  138.  *                      MAINSTM2,mem_ctl[1].displaystr,
  139.  *                      MAINSTM3,mem_ctl[2].displaystr,
  140.  *                      MAINSTM4,mem_ctl[3].displaystr,
  141.  *                      MAINSTM5,mem_ctl[4].displaystr,
  142.  *                      -1);
  143.  *
  144.  *   The rsc_sstrings routine is an AESFAST library routine that sets the
  145.  *   ob_spec pointers for 1-n strings within a dialog tree.
  146.  *************************************************************************/
  147.  
  148. void
  149. prg_init()
  150. {
  151.         int                dmy;
  152.         register int       objcounter;
  153.         register int       strcounter;
  154.         register OBJECT    *pobj;
  155.         register MEM_BLOCK *pblock;
  156.         
  157. /*
  158.  * call AES init, then try to load the resource file.  if the RSC load
  159.  * fails, go whine at the user and exit.
  160.  */
  161.  
  162.         appl_init();
  163.         
  164.         if (!rsrc_load("MEMFIND.RSC")) {
  165.                 form_alert(no_rsrc_alert);
  166.                 prg_exit(NO_RSRC);
  167.         }
  168.  
  169. /*
  170.  * get the address of the dialog tree
  171.  */
  172.      
  173.         rsrc_gaddr(R_TREE, MAINTREE, &maintree);
  174.    
  175. /*
  176.  * connect up the links between the memory control structures and the
  177.  * object structures... (see notes above).
  178.  *
  179.  * go through the object tree, and each time we encounter an object
  180.  * with the right extended object type, connect that object's ob_spec
  181.  * pointer to the display string in the memory control structure, and
  182.  * make note of the object's index in the objlink field of the memory
  183.  * control structure.  normally, only the ob_spec link would be made,
  184.  * but for our application we need to be able to set an object's flags
  185.  * to HIDETREE if we discover an empty block in the memory control struct.
  186.  *
  187.  * the loop control here will stop if we run out of memory control blocks
  188.  * or if we run out of objects in the tree.  this means that if someone
  189.  * munges up the resource file and removes some of our string objects,
  190.  * then some memory blocks won't be displayed, but at least nothing dies.
  191.  */     
  192.         objcounter = strcounter = 0;
  193.         do      {
  194.                 pobj = &maintree[objcounter];
  195.                 if (1 == (pobj->ob_type >> 8)) {
  196.                         pblock = &mem_ctl[strcounter];
  197.                         pobj->ob_spec  = (long)pblock->displaystr;
  198.                         pblock->objlink = objcounter;
  199.                         strcounter++;
  200.                 }
  201.                 objcounter++;
  202.         } while ( (strcounter < NUM_BLOCKS) &&
  203.                   (!(pobj->ob_flags & LASTOB)) );
  204.  
  205. /* 
  206.  * init all done, change the mouse from a busy-bee to an arrow.
  207.  */
  208.         graf_mouse(ARROW, 0L);
  209. }
  210.  
  211. /**************************************************************************
  212.  *
  213.  * dial_do - Generic dialog handler.
  214.  *
  215.  *  This routine handles dialog interaction for any dialog box.  If the
  216.  *  d-box has editable text objects, pass this routine the object index
  217.  *  of the first text object to edit.  If there are no edit objects, just
  218.  *  pass a zero.  This routine assumes that a form_center call has already
  219.  *  been done (I always do the center calls during init processing, since
  220.  *  it makes no sense to center the same dialog box multiple times if the
  221.  *  dialog is invoked multiple times).  This routine does NOT do the 
  222.  *  annoying graphics calls (FMD_GROW and FMD_SHRINK).  You can put them
  223.  *  in if you have the patience to watch little lines zoom around on the
  224.  *  screen.
  225.  *
  226.  *  Another library routine, 'objst_change' is used to de-select the exit
  227.  *  object.  The object is not changed visually on the screen (it looks
  228.  *  ugly if you do it that way), but will display as non-selected the next
  229.  *  time the dialog box is displayed.  It should be noted that it is 
  230.  *  probably faster to de-select the object with a line of code like:
  231.  *    tree[exitobj].ob_state &= ~SELECTED;
  232.  *  but I think the function call is more readable.
  233.  *
  234.  *  This routine returns the index of the object used to exit the dialog.
  235.  *************************************************************************/
  236.  
  237. int
  238. dial_do(tree, startedit)
  239.         register OBJECT *tree;
  240.         int             startedit;
  241. {
  242.         int   exitobj;
  243.         GRECT cliprect; 
  244.        
  245.         frmx_center(maintree, &cliprect);
  246.         
  247.         form_dial(FMD_START, 0,0,0,0, cliprect);
  248.  
  249.         objc_draw(tree, R_TREE, MAX_DEPTH, cliprect);
  250.  
  251.         exitobj = form_do(tree, startedit);
  252.  
  253.         objst_change(tree, exitobj, ~SELECTED, FALSE);
  254.  
  255.         form_dial(FMD_FINISH, 0,0,0,0, cliprect);
  256.         
  257.         return exitobj;
  258. }
  259.  
  260. /**************************************************************************
  261.  *
  262.  * main routine - Call init routine, map out the memory blocks, display
  263.  *  the map, then call the exit routine.
  264.  *
  265.  *************************************************************************/
  266.  
  267. main()
  268. {
  269.         register int       counter;
  270.         register int       kbytes;
  271.         register MEM_BLOCK *pblock;
  272.  
  273. /*
  274.  * go do GEM initialization...
  275.  */
  276.  
  277.         prg_init();
  278.  
  279. /*
  280.  * find the biggest memory blocks available in the system.  for each
  281.  * loop iteration, ask TOS what the biggest available memory block is.
  282.  * if TOS returns a zero, we've found all available fragments already,
  283.  * so set the corresponding object's flags to HIDETREE so it won't 
  284.  * display anything.  (if the objlink field in the memory control struct
  285.  * points to object 0 (R_TREE), we don't set the HIDE flag, because the
  286.  * whole dialog box would be hidden.  this is only to handle the case
  287.  * where we ran out of strings in the object tree before we ran out of
  288.  * memory control blocks when we were setting the links in the init 
  289.  * routine. any links that didn't get set would be 0.)
  290.  *
  291.  * when a block of memory is found, allocate it, and save its pointer so
  292.  * we can free it later.  format the display string to contain the memory
  293.  * block's address and size, then continue with the next loop iteration. 
  294.  */
  295.  
  296.         for (counter = 0; counter < NUM_BLOCKS; counter++) {
  297.         
  298.                 pblock = &mem_ctl[counter];
  299.                 pblock->lmem = Malloc(-1L);
  300.  
  301.                 if (pblock->lmem > 0L) {
  302.                         kbytes = (int)(pblock->lmem / 1024);
  303.                         
  304.                         if (kbytes == 0)        /* fake a small block   */
  305.                                 kbytes = 1;     /* into looking like 1k */
  306.  
  307.                         pblock->pmem = (char *)Malloc(pblock->lmem);
  308.  
  309.                         sprintf(pblock->displaystr, map_template, 
  310.                                   pblock->pmem, kbytes );
  311.                 } 
  312.                 else { /* memory-block size == 0 */
  313.                         if (pblock->objlink != R_TREE) {
  314.                                 objfl_change(maintree, pblock->objlink, 
  315.                                                 HIDETREE, FALSE);
  316.                         }
  317.                 }
  318.         }
  319.  
  320. /* 
  321.  * we've built and formatted the memory map, so now we can free all
  322.  * the blocks we allocated.
  323.  */
  324.  
  325.         for (counter = 0; counter < NUM_BLOCKS; counter++) {
  326.                 Mfree(mem_ctl[counter].pmem);
  327.         }
  328.  
  329. /*
  330.  * now display the results of the mapping, and exit.
  331.  */
  332.  
  333.         dial_do(maintree,0);
  334.         
  335.         prg_exit(0);
  336. }
  337.